/*
 * AbstractBaseChart.java
 * Android-Charts
 *
 * Created by limc on 2013.
 *
 * Copyright 2011 limc.cn All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cn.limc.ohoscharts.view;


import cn.limc.ohoscharts.common.IChart;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.window.service.Display;
import ohos.agp.window.service.DisplayAttributes;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;

import java.util.Optional;

/**
 * <p>
 * Base view of all charts
 * </p>
 * <p>
 * 全部チャートのベースオブジェクト。
 * </p>
 * <p>
 * 所有图表对象的基类
 * </p>
 *
 * @author limc
 * @version v1.0 2011/05/29 15:17:50
 */
public abstract class AbstractBaseChart extends Component implements IChart,
        Component.EstimateSizeListener {
  public static final String LOG_TAG = "AbstractBaseChart";

  /**
   * <p>
   * default background color
   * </p>
   * <p>
   * 背景の色のデフォルト値
   * </p>
   * <p>
   * 默认背景色
   * </p>
   */
  public static final int DEFAULT_BACKGROUND_COLOR = Color.BLACK.hashCode();

  /**
   * <p>
   * Should display the border?
   * </p>
   * <p>
   * 枠を表示するか?
   * </p>
   * <p>
   * 默认控件是否显示边框
   * </p>
   */
  public static final boolean DEFAULT_DISPLAY_BORDER = Boolean.TRUE;

  /**
   * <p>
   * default color of text for the longitude　degrees display
   * </p>
   * <p>
   * 経度のタイトルの色のデフォルト値
   * </p>
   * <p>
   * 默认经线刻度字体颜色
   * </p>
   */
  public static final int DEFAULT_BORDER_COLOR = Color.RED.hashCode();

  public static final float DEFAULT_BORDER_WIDTH = 1f;

  /**
   * <p>
   * Should display the border?
   * </p>
   * <p>
   * 枠を表示するか?
   * </p>
   * <p>
   * 控件是否显示边框
   * </p>
   */
  protected boolean displayBorder = DEFAULT_DISPLAY_BORDER;

  /**
   * <p>
   * Color of grid‘s border line
   * </p>
   * <p>
   * 枠線の色
   * </p>
   * <p>
   * 图边框的颜色
   * </p>
   */
  protected int borderColor = DEFAULT_BORDER_COLOR;

  protected float borderWidth = DEFAULT_BORDER_WIDTH;

  /*
   * (non-Javadoc)
   *
   * @param context
   *
   * @see ohos.view.View#BaseChart(Context)
   */
  public AbstractBaseChart(Context context) {
    super(context);
    addDrawTask(this::onDraw);
    setEstimateSizeListener(this::onEstimateSize);
  }


  /*
   * (non-Javadoc)
   *
   * @param context
   *
   * @param attrs
   *
   * @see ohos.view.View#BaseChart(Context, AttributeSet)
   */
  public AbstractBaseChart(Context context, AttrSet attrs) {
    super(context, attrs);
    addDrawTask(this::onDraw);
    setEstimateSizeListener(this::onEstimateSize);
  }

  /*
   * (non-Javadoc)
   *
   * @param context
   *
   * @param attrs
   *
   * @param defStyle
   *
   * @see ohos.view.View#BaseChart(Context, AttributeSet, int)
   */
  public AbstractBaseChart(Context context, AttrSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    addDrawTask(this::onDraw);
    setEstimateSizeListener(this::onEstimateSize);
  }

  private void onDraw(Component component, Canvas canvas) {
    if (this.displayBorder) {
      drawBorder(canvas);
    }
  }


  /**
   * <p>
   * draw border
   * </p>
   * <p>
   * グラプのボーダーを書く
   * </p>
   * <p>
   * 绘制边框
   * </p>
   *
   * @param canvas .
   */
  protected void drawBorder(Canvas canvas) {
    Paint mPaint = new Paint();
    mPaint.setColor(new Color(borderColor));
    mPaint.setStrokeWidth(borderWidth);
    mPaint.setStyle(Paint.Style.STROKE_STYLE);
    // draw a rectangle
    canvas.drawRect(borderWidth / 2, borderWidth / 2, super.getWidth()
            - borderWidth / 2, super.getHeight() - borderWidth / 2, mPaint);
  }

  /*
   * (non-Javadoc)
   *
   * @param widthMeasureSpec
   *
   * @param heightMeasureSpec
   *
   * @see ohos.view.View#onMeasure(int, int)
   */
  private int DEFAULT_WIDTH;
  private int DEFAULT_HEIGHT;


  @Override
  public boolean onEstimateSize(int widthMeasureSpec, int heightMeasureSpec) {
    if (DEFAULT_WIDTH == 0) {
      Optional<Display>
              display = DisplayManager.getInstance().getDefaultDisplay(this.getContext());
      DisplayAttributes displayAttributes = display.get().getAttributes();
      DEFAULT_WIDTH = displayAttributes.width;
    }

    int width = measureSize(1, DEFAULT_WIDTH, widthMeasureSpec);
    int height = measureSize(1, DEFAULT_HEIGHT, heightMeasureSpec);
    setEstimatedSize(width, height);
    return false;
  }


  /**
   * 测绘measure
   *
   * @param specType    1为宽， 其他为高
   * @param contentSize 默认值
   */
  private int measureSize(int specType, int contentSize, int measureSpec) {
    int result;
    //获取测量的模式和Size
    int specMode = EstimateSpec.getMode(measureSpec);
    int specSize = EstimateSpec.getSize(measureSpec);

    if (specMode == EstimateSpec.PRECISE) {
      result = Math.min(contentSize, specSize);
    } else {
      result = contentSize;

      if (specType == 1) {
        // 根据传人方式计算宽
        result += (getPaddingLeft() + getPaddingRight());
      } else {
        // 根据传人方式计算高
        result += (getPaddingTop() + getPaddingBottom());
      }
    }

    return result;
  }




	/*
	 * (non-Javadoc)
	 * 
	 * @param gainFocus
	 * 
	 * @param direction
	 * 
	 * @param previouslyFocusedRect
	 * 
	 * @see ohos.view.View#onFocusChanged(boolean, int,
	 * ohos.graphics.Rect)
    	 */
  //	@Override
  //	protected void onFocusChanged(boolean gainFocus, int direction,
  //			Rect previouslyFocusedRect) {
  //		super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
  //	}


  private int measureWidth(int measureSpec) {
    int result = 0;
    int specMode = MeasureSpec.getMode(measureSpec);
    int specSize = MeasureSpec.getSize(measureSpec);

    if (specMode == MeasureSpec.PRECISE) {
      result = specSize;
    } else if (specMode == MeasureSpec.ESTIMATED_STATE_BIT_MASK) {
      result = Math.min(result, specSize);
    }
    return result;
  }

  private int measureHeight(int measureSpec) {
    int result = 0;
    int specMode = MeasureSpec.getMode(measureSpec);
    int specSize = MeasureSpec.getSize(measureSpec);
    if (specMode == MeasureSpec.PRECISE) {
      result = specSize;
    } else if (specMode == MeasureSpec.ESTIMATED_STATE_BIT_MASK) {
      result = Math.min(result, specSize);
    }
    return result;
  }

  // protected int[] getStyleableName(Context context) {
  // try {
  // StringBuilder sbStyleable = new StringBuilder();
  // sbStyleable.append(context.getApplicationContext().getPackageName());
  // sbStyleable.append(".R$styleable");
  // String styleable = sbStyleable.toString();
  // int[] id =
  // (int[])Class.forName(styleable).getField(STYLEABLE_NAME).get(null);
  // return id;
  // }catch (Exception e) {
  // return null;
  // }
  // }
  //
  // protected int getStyleableAttrId(Context context , String attr) {
  // try {
  // StringBuilder sbStyleable = new StringBuilder();
  // sbStyleable.append(context.getApplicationContext().getPackageName());
  // sbStyleable.append(".R$styleable");
  // String styleable = sbStyleable.toString();
  //
  // Class<?> clazz = Class.forName(styleable);
  // int[] id = (int[])clazz.getField(STYLEABLE_NAME).get(null);
  //
  // StringBuilder sbAttribute = new StringBuilder();
  // sbAttribute.append(STYLEABLE_NAME);
  // sbAttribute.append("_");
  // sbAttribute.append(attr);
  // String attribute = sbAttribute.toString();
  //
  // int index = clazz.getField(attribute).getInt(null);
  // return id[index];
  // }catch (Exception e) {
  // return 0;
  // }
  // }


  /**
   * @return the displayBorder
   */
  public boolean isDisplayBorder() {
    return displayBorder;
  }

  /**
   * @param displayBorder the displayBorder to set
   */
  public void setDisplayBorder(boolean displayBorder) {
    this.displayBorder = displayBorder;
  }

  /**
   * @return the borderColor
   */
  public int getBorderColor() {
    return borderColor;
  }

  /**
   * @param borderColor the borderColor to set
   */
  public void setBorderColor(int borderColor) {
    this.borderColor = borderColor;
  }

  /**
   * @return the borderWidth
   */
  public float getBorderWidth() {
    return borderWidth;
  }

  /**
   * @param borderWidth the borderWidth to set
   */
  public void setBorderWidth(float borderWidth) {
    this.borderWidth = borderWidth;
  }
}
